package com.corticon.dialogs.web.designer;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.util.HtmlUtils;
import com.corticon.dialogs.dao.DataValidationDAO;
import com.corticon.dialogs.dao.DataTypeDAO;
import com.corticon.dialogs.dao.QuestionAvailabilityTypeDAO;
import com.corticon.dialogs.dao.QuestionDAO;
import com.corticon.dialogs.dao.QuestionStatusTypeDAO;
import com.corticon.dialogs.dao.ResponseEntryDAO;
import com.corticon.dialogs.dao.ResponseTypeDAO;
import com.corticon.dialogs.dao.UiControlDAO;

import com.corticon.dialogs.dao.UnitsDAO;
import com.corticon.dialogs.dao.UserDAO;
import com.corticon.dialogs.dao.UserGroupDAO;
import com.corticon.dialogs.dao.hibernate.QuestionManager;
import com.corticon.dialogs.model.DataValidation;

import com.corticon.dialogs.model.DataType;
import com.corticon.dialogs.model.PermissionType;
import com.corticon.dialogs.model.Question;
import com.corticon.dialogs.model.QuestionAvailabilityType;
import com.corticon.dialogs.model.QuestionSet;
import com.corticon.dialogs.model.QuestionStatusType;
import com.corticon.dialogs.model.ResponseEntry;
import com.corticon.dialogs.model.ResponseType;
import com.corticon.dialogs.model.UiControl;
import com.corticon.dialogs.model.Units;
import com.corticon.dialogs.model.User;
import com.corticon.dialogs.model.UserGroup;
import com.corticon.dialogs.util.GenericFunction;
import com.corticon.dialogs.util.MyComparator;
import com.corticon.dialogs.util.Pager;
import com.corticon.dialogs.util.security.CustomUserDetails;
import com.corticon.dialogs.util.security.SecurityUtils;
import com.corticon.dialogs.validation.ValidationMessageFormatter;
import com.corticon.dialogs.validation.designer.QuestionValidator;
import com.corticon.dialogs.web.BaseController;
import org.springframework.validation.FieldError;

/**
 * question controller
 * 
 * @author heweiya
 * 
 */
@Controller
@SessionAttributes( { "question" })
public class QuestionController extends BaseController {

	private static final Log logger = LogFactory.getLog(QuestionController.class);
	private final String[] MessageKeys = { "questionerror" };
	private final String MESSAGE_KEY = "questionerror";
	private final String[] defaultQuestionMessageKeys = { "questionmessage" };
	private final String DEFAULT_QUESTION_MESSAGE_KEY = "questionmessage";
	private final String MESSAGE_WHEREUSERD_KEY = "whereuserdmessage";
	private final String SEARCH_KEYWORD = "questionSearchKey";
	// RequestURIs
	private final String NEW_VERSION_REQUEST = "newversion";
	private final String COPY_REQUEST = "copy";
	private final String WHERE_USED_REQUEST = "whereused";
	private final String RETIRE_REQUEST = "retire";
	private final String MOVE_UP_REQUEST = "moveup";
	private final String MOVE_DOWN_REQUEST = "movedown";
	private final String DEL_RESPONSE_REQUEST = "delresponse";
	private final String ADD_RESPONSE_REQUEST = "addresponse";
	private final String CHECK_HAVE_REQUEST = "checkhaveresponse";
	private final String CHECK_REQUEST = "checkresponse";
	private final String LIST_RESPONSE_REQUEST = "listresponse";
	private final String CHECK_QUESTION_STATUE = "checkquestion";
	private final String DEL_REQUEST = "delete";
	private final String CHECK_CREATE_REQUEST = "checkcreate";
	private final String SEARCH_REQUEST = "search";
	// message
	private String createQuestionFirstMessage = "question.create.firstmsg";
	private String createQuestionSuccessMessage = "question.create.success";
	private String editQuestionSuccessMessage = "question.edit.success";
	private String copyQuestionSuccessMessage = "question.copy.success";
	private String createNewVersionQuestionFirstMessage = "question.create.newversion1st";
	private String createNewVersionQuestionMessage = "question.create.newversionmsg";
	private String emptyQuestionMessage = "question.empty";
	private String retiredMessage = "question.create.retired";
	private String lockedMessage = "question.create.locked";
	private String copyMessage = "question.create.copymsg";
	private String questionFoundMessage = "question.found";
	private String questionRetireConfirmMessage = "question.retire.confirm";
	private String questionRetireNoteMessage = "question.retirenote.empty";
	private String questionRetireSuccessMessage = "question.retire.success";
	private String questionRetireNoteLenMessage = "questionBase.retirednote.length";
	private String includeMessage = "question.include.page";
	private String deletedMessage = "question.delete.success";
	private String publicCancelMessage = "general.action.cancel";
	private String responseTypeMessage = "question.responsetype.empty";
	private String uiControlMessage = "question.uicontrol.empty";
	private String dataTypeMessage = "question.datatype.empty";
	private String customMessage = "question.customitem.empty";
	private String invalidMessage = "question.invalid.empty";
	private String selectResponseMessage = "question.selectresponse.select";
	private String responseLableMessage = "question.responselable.empty";
	private String responseValueMessage = "question.responsevalue.empty";
	private String digitalMessage = "questin.digital.only";
	private String integerMessage = "question.integer.only";
	private String dateMessage = "question.date.only";
	private String maxSelectMessage = "questionmaxselect.check";
	private String maxResponseInputMessage = "question.maxresponseinput.check";
	private String maxResponseMessage = "question.maxresponse.check";
	private String pageRetiredMessage = "questionset.list.retired";
	private String pageLockedMessage = "questionset.list.locked";
	private String emptyTextAreaWidthMessage = "question.textareawidth.empty";
	private String emptyTextAreaRowsMessage = "question.textarearows.empty";

	// DAOs
	@Resource
	private UserDAO userDAO;
	@Resource
	private UserGroupDAO userGroupDAO;
	@Resource
	private QuestionDAO questionDAO;
	@Resource
	private QuestionManager questionManager;
	@Resource
	private ResponseTypeDAO responseTypeDAO;
	@Resource
	private DataValidationDAO dataValidationDAO;
	@Resource
	private UnitsDAO unitsDAO;
	@Resource
	private UiControlDAO uiControlDAO;
	@Resource
	private DataTypeDAO dataTypeDAO;
	@Resource
	private ResponseEntryDAO responseEntryDAO;
	@Resource
	private QuestionAvailabilityTypeDAO questionAvailabiliTytypeDAO;
	@Resource
	private QuestionStatusTypeDAO questionStatusTypeDAO;
	// Other resources
	@Resource
	private MessageSource messageSource;
	@Resource
	private ValidationMessageFormatter validationMessageFormatter;
	private QuestionValidator questionValidator;

	/**
	 * Instantiate the validators after the construct method.
	 */
	@PostConstruct
	private void buildValidators() {
		questionValidator = new QuestionValidator(validationMessageFormatter);
	}

	@RequestMapping(value = LIST_REQUEST, method = RequestMethod.GET)
	public String listQuestions(@RequestParam(required = false)
	Integer page, ModelMap model, HttpServletRequest request) {
		// loginuser && security
		// Get the permission list for the current user.
		List<String> permissions = SecurityUtils.getCurrentUserPermissions();
		// Get the current user.
		CustomUserDetails currentUserDetails = SecurityUtils.getCurrentUser();
		User currentUser = userDAO.findById(currentUserDetails.getUsername());
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			request.getSession().removeAttribute("ResponseTypeId");
		}
		String checkSearch = "";
		if (request.getParameterValues("checkSearch") != null) {
			if (request.getSession().getAttribute(SEARCH_KEYWORD) != null) {
				String searchPara = (String) request.getSession().getAttribute(SEARCH_KEYWORD);
				searchPara = searchPara.replace("keywords", "keyword");
				return redirectPrefix + this.SEARCH_REQUEST + requestSuffix + "?" + searchPara;
			}
		}

		// page
		Pager pager = constructPager(page, request);
		// Pager pager = new Pager();
		pager = setPagerSort(pager, "questionId", request);
		request.setAttribute("pager", pager);
		request.setAttribute("order", request.getParameter("sortBy"));
		request.setAttribute("column", request.getParameter("sortColumn"));

		request.setAttribute(PAGER_NAME, pager);
		// list
		List<Question> questions = new ArrayList<Question>();
		// Create a question example.
		Question qsExample = new Question();

		// If the current user is sys admin, he can view all of the question
		// sets.
		if (permissions.contains(PermissionType.SYS_ADMIN.value())) {
			pager.setNumOfRecords(questionDAO.getCountAll());
			questions = questionDAO.getPageOfDataAll(pager);
		} else if (permissions.contains(PermissionType.PORTAL_USER.value())) {
			// If the current user is portal user, he can only view the question
			// sets belong to him.
			qsExample.setModifiedBy(currentUser);
			pager.setNumOfRecords(questionDAO.getCountByExample(qsExample, "version"));
			questions = questionDAO.getPageOfDataByExample(qsExample, pager, "version");
		} else {
			// If the current user is in other roles, he can only view the
			// question sets belong to
			// his group.
			UserGroup group = userGroupDAO.load(currentUserDetails.getGroupName());
			questions = questionDAO.getPageOfDataByGroup(group, pager);
			pager.setNumOfRecords(questionDAO.getCountByGroup(group));
		}
		loadUsersAndGroupsInfoByPermission(currentUserDetails, request);
		readMessages(defaultQuestionMessageKeys, request);
		if (questions != null && questions.size() > 0) {
			model.addAttribute("questions", questions);
			request.setAttribute(MESSAGE_KEY, getMessage(String.valueOf(pager.getNumOfRecords()), questionFoundMessage));
		} else {
			request.setAttribute(MESSAGE_KEY, getMessage("", publicNotFoundMessage));
		}
		String from = "";
		if (request.getParameterValues("from") != null) {
			from = request.getParameterValues("from")[0];
			request.setAttribute(DEFAULT_QUESTION_MESSAGE_KEY, getMessage("", publicCancelMessage));
		}
		request.setAttribute("Msg_retire", getMessage("", retiredMessage));
		request.setAttribute("Msg_lock", getMessage("", lockedMessage));
		model.addAttribute("from", from);
		return "designer.question.list";
	}

	@RequestMapping(value = SEARCH_REQUEST, method = RequestMethod.GET)
	public String search(@RequestParam(required = false)
	Integer page, ModelMap model, HttpServletRequest request) {

		CustomUserDetails currentUser = SecurityUtils.getCurrentUser();
		List<String> permissions = currentUser.getPermissions();

		// Get the search criterions.
		String keywords = request.getParameter("keyword");
		String availability = request.getParameter("availability");
		availability = availability == null ? "" : availability;
		String status = request.getParameter("status");
		status = status == null ? "" : status;
		String username = request.getParameter("user");
		username = username == null ? "" : username;
		String groupName = request.getParameter("group");
		groupName = groupName == null ? "" : groupName;
		model.addAttribute("selectedAvail", availability);
		model.addAttribute("selectedStatus", status);
		model.addAttribute("selectedUser", username);
		model.addAttribute("selectedGroup", groupName);
		model.addAttribute("keyword", keywords);
		// Construct the pager object.
		Pager pager = constructPager(page, request);
		String requestParameters = "&keyword=" + keywords + "&availability=" + availability + "&status=" + status;
		// Pager pager = new Pager();
		pager = setPagerSort(pager, "questionId", request);
		request.setAttribute("pager", pager);
		request.setAttribute("order", request.getParameter("sortBy"));
		request.setAttribute("column", request.getParameter("sortColumn"));

		// Construct the search criterions according to the role of the current
		// user. And set the
		// username and groupname params into the request scope.

		if (permissions.contains(PermissionType.GROUP_ADMIN.value()) || permissions.contains(PermissionType.AUTHOR.value()) || permissions.contains(PermissionType.REVIEWER.value())) {
			groupName = currentUser.getGroupName();
			requestParameters = requestParameters + "&group=" + groupName;
		} else if (permissions.contains(PermissionType.PORTAL_USER.value())) {
			username = currentUser.getUsername();
			requestParameters = requestParameters + "&user=" + username;
		} else {
			requestParameters = requestParameters + "&user=" + username + "&group=" + groupName;
		}

		// Set the search criterions into the pager object.
		pager.setRequestParameters(pager.getRequestParameters() + requestParameters);
		request.getSession().setAttribute(SEARCH_KEYWORD, pager.getRequestParameters() + requestParameters);
		List<Question> results = new ArrayList<Question>();

		if (StringUtils.isNotEmpty(username) && StringUtils.isNotEmpty(groupName)) {
			User searchedUser = userDAO.findById(username);
			if (searchedUser != null && searchedUser.getUserGroup().getName().equals(groupName)) {
				// Call the search method in Question Set DAO to search. Then
				// set results into the request
				// scope.
				results = questionDAO.search(keywords, availability, status, username, groupName, pager);
			}
		} else {
			results = questionDAO.search(keywords, availability, status, username, groupName, pager);
		}

		// Set the pager and results into the request scope.
		request.setAttribute("pager", pager);
		request.setAttribute("questions", results);
		// Call the method to get infos about User and Group according to the
		// role of the current
		// user. Then set them into the request scope.
		loadUsersAndGroupsInfoByPermission(currentUser, request);
		readMessages(defaultQuestionMessageKeys, request);
		if (results != null && results.size() > 0) {
			request.setAttribute(MESSAGE_KEY, getMessage(String.valueOf(pager.getNumOfRecords()), publicFoundMessage));
		} else {
			request.setAttribute(MESSAGE_KEY, getMessage("", publicNotFoundMessage));
		}
		request.setAttribute("Msg_retire", getMessage("", retiredMessage));
		request.setAttribute("Msg_lock", getMessage("", lockedMessage));
		return "designer.question.list";
	}

	/**
	 * The method is used to render the page before display the create question
	 * page. If you want to put a model into requestScope, use method
	 * addAttribute in {@link ModelMap}.
	 * 
	 * @param model
	 * @return
	 */
	@Transactional(readOnly = true)
	@RequestMapping(value = CREATE_REQUEST, method = RequestMethod.GET)
	public String entryCreateQuestion(ModelMap model, HttpServletRequest request) {
		// loginuser
		CustomUserDetails currentAdmin = SecurityUtils.getCurrentUser();
		// clean session(ResponseTypeId)
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			request.getSession().removeAttribute("ResponseTypeId");
		}
		// init question
		Question question = initQuestion(currentAdmin.getUsername());
		createFirst(model);
		// addMessages(createQuestionFirstMessage, request, messageSource,
		// null);
		readMessages(defaultQuestionMessageKeys, request);
		request.setAttribute(MESSAGE_KEY, getMessage("", createQuestionFirstMessage));
		errorMessage(model);
		model.addAttribute("question", question);
		model.addAttribute("currentAdmin", currentAdmin);
		return getViewNameByRequestURI(request);
	}

	/**
	 * Process the form submit of Create question Function.
	 * 
	 * @param submitAction
	 *            The type of the action after submit, such as submit, submit
	 *            then new, and so on.
	 * @param newUser
	 *            The html form data bind into this object.
	 * @param errors
	 *            {@link Errors} object, used by the spring validator.
	 * @param sessionStatus
	 *            {@link SessionStatus} used to control the status of the beans
	 *            in session scope.
	 * @return
	 */
	@Transactional()
	@RequestMapping(value = { CREATE_REQUEST, EDIT_REQUEST, COPY_REQUEST, NEW_VERSION_REQUEST }, method = RequestMethod.POST)
	public String processCreateQuestion(@RequestParam
	String submitAction, @ModelAttribute("question")
	Question question, Errors errors, ModelMap model, HttpServletRequest request, SessionStatus sessionStatus) {
		// login user
		CustomUserDetails currentAdmin = SecurityUtils.getCurrentUser();
		readMessages(defaultQuestionMessageKeys, request);
		/**
		 * if
		 * (questionManager.findSameQuestion(question.getRefId(),question.getVersion())) {
		 * addMessages(DEFAULT_QUESTION_MESSAGE_KEY +
		 * "=questionBase.refIdAndVersionDuplicate", request, messageSource,
		 * null); readMessages(defaultQuestionMessageKeys, request); return
		 * redirectPrefix + COPY_REQUEST + requestSuffix; }
		 */
		if (request.getParameterValues("name") != null) {
			question.setName(request.getParameterValues("name")[0]);
		}
		if (request.getParameterValues("vocabularyname") != null) {
			question.setVocabularyname(request.getParameterValues("vocabularyname")[0]);
		}
		if (request.getParameterValues("text") != null) {
			question.setText(request.getParameterValues("text")[0]);
		}
		if (request.getParameterValues("helpText") != null) {
			question.setHelpText(request.getParameterValues("helpText")[0]);
		}
		if (request.getParameterValues("description") != null) {
			question.setDescription(request.getParameterValues("description")[0]);
		}
		// error && message
		Map<String, List<String>> errorsMessages = questionValidator.invokeValidate(question, errors, request.getLocale());
		request.setAttribute("errors", errorsMessages);

		if (errors.hasErrors()) {
			createFirst(model);
			request.getSession().removeAttribute("ResponseTypeId");
			return getViewNameByRequestURI(request);
		}

		question.setName(request.getParameterValues("name")[0]);
		// branch begin
		String TypeName = "";
		if (request.getParameterValues("Responsetype") != null) {
			TypeName = request.getParameterValues("Responsetype")[0];
		}

		String UiCustomName = "";
		if (request.getParameterValues("Custom_UIControl") != null) {
			UiCustomName = request.getParameterValues("Custom_UIControl")[0];
		}
		String UiDynamicName = "";
		if (request.getParameterValues("Dynamic_UIControl") != null) {
			UiDynamicName = request.getParameterValues("Dynamic_UIControl")[0];
		}
		// get session
		String ResponseTypeId = "";
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
		}

		String DateType = "";
		if (TypeName.equals("Custom")) {
			if (request.getParameterValues("Custom_DataType") != null) {
				DateType = request.getParameterValues("Custom_DataType")[0];
			}
			// "Radio Button" "Dropdown""Check Box" => set it
			// "Text Box" "Text Area" =>new response type
			if (UiCustomName.equals("Radio Button") || UiCustomName.equals("Dropdown") || UiCustomName.equals("Check Box")) {
				if (!ResponseTypeId.equals("")) {
					ResponseType type = responseTypeDAO.findById(Long.valueOf(ResponseTypeId));
					question.setResponseType(type);
					if (!DateType.equals("0")) {
						type.setDataType(dataTypeDAO.findById(DateType));
					}
				}
				String maxResponses_sq_checkbox = request.getParameterValues("maxResponses_sq_checkbox")[0];
				if (!maxResponses_sq_checkbox.equals("")) {
					question.setMaxResponses(Long.valueOf(maxResponses_sq_checkbox));
				}
			}
			if (UiCustomName.equals("Text Box") || UiCustomName.equals("Text Area")) {

				if (DateType.equals("0")) {
					String maxResponses_sq_checkbox = request.getParameterValues("maxResponses_sq_checkbox")[0];
					if (!maxResponses_sq_checkbox.equals("")) {
						question.setMaxResponses(Long.valueOf(maxResponses_sq_checkbox));
					}
				} else {
					// text box/text area/integer/float/
					ResponseType type = new ResponseType();
					UiControl ui = questionManager.getUIbyName(UiCustomName);
					type.setUicontrol(ui);
					// text area string
					if (UiCustomName.equals("Text Area") && DateType.equals("String")) {
						String minResponseValue_sq_textarea = request.getParameterValues("minResponseValue_sq_textarea")[0];
						String maxResponseValue_sq_textarea = request.getParameterValues("maxResponseValue_sq_textarea")[0];
						question.setMinResponseValue(minResponseValue_sq_textarea);
						question.setMaxResponseValue(maxResponseValue_sq_textarea);
						if (request.getParameterValues("Mask_textarea") != null) {
							String validation_exp = request.getParameterValues("Mask_textarea")[0];
							if (!validation_exp.equals("") && !validation_exp.equals("0")) {
								DataValidation validation = dataValidationDAO.findById(validation_exp);
								type.setDataValidation(validation);
							}

						}
						DataType datatype = dataTypeDAO.findById("String");
						type.setDataType(datatype);
					}
					// text box string
					if (UiCustomName.equals("Text Box") && DateType.equals("String")) {
						String minResponseValue_sq_string = request.getParameterValues("minResponseValue_sq_string")[0];
						String maxResponseValue_sq_string = request.getParameterValues("maxResponseValue_sq_string")[0];
						String width_string = request.getParameterValues("width_string")[0];
						question.setMinResponseValue(minResponseValue_sq_string);
						question.setMaxResponseValue(maxResponseValue_sq_string);
						question.setWidth(width_string);
						if (request.getParameterValues("Mask_string") != null) {
							String validation_exp = request.getParameterValues("Mask_string")[0];
							if (!validation_exp.equals("") && !validation_exp.equals("0")) {
								DataValidation validation = dataValidationDAO.findById(validation_exp);
								type.setDataValidation(validation);
							}

						}
						if (request.getParameterValues("Units_string") != null) {
							String u1 = request.getParameterValues("Units_string")[0];
							u1 = HtmlUtils.htmlEscape(u1);
							if (!u1.equals("")) {
								Units units = unitsDAO.findById(u1);
								if (units == null) {
									units = new Units();
									units.setCode(u1);
									units.setName(u1);
									units.setDescription(u1);
									unitsDAO.save(units);
								}
								type.setUnits(units);
							}

						}
						DataType datatype = dataTypeDAO.findById("String");
						type.setDataType(datatype);
					}
					if (DateType.equals("Date")) {
						String minResponseValue_sq_date = request.getParameterValues("minResponseValue_sq_date")[0];
						String maxResponseValue_sq_date = request.getParameterValues("maxResponseValue_sq_date")[0];
						question.setMinResponseValue(minResponseValue_sq_date);
						question.setMaxResponseValue(maxResponseValue_sq_date);
						DataType datatype = dataTypeDAO.findById("Date");
						type.setDataType(datatype);
					}

					if (DateType.equals("Integer")) {
						String minResponseValue_sq_int = request.getParameterValues("minResponseValue_sq_int")[0];
						String maxResponseValue_sq_int = request.getParameterValues("maxResponseValue_sq_int")[0];
						question.setMinResponseValue(minResponseValue_sq_int);
						question.setMaxResponseValue(maxResponseValue_sq_int);
						if (request.getParameterValues("Units_int") != null) {
							String u1 = request.getParameterValues("Units_int")[0];
							// if (!u1.equals("") || !u1.equals("0")) {
							// Units units = unitsDAO.findById(u1);
							// type.setUnits(units);
							// }
							u1 = HtmlUtils.htmlEscape(u1);
							if (!u1.equals("")) {
								Units units = unitsDAO.findById(u1);
								if (units == null) {
									units = new Units();
									units.setCode(u1);
									units.setName(u1);
									units.setDescription(u1);
									unitsDAO.save(units);
								}
								type.setUnits(units);
							}

						}
						DataType datatype = dataTypeDAO.findById("Integer");
						type.setDataType(datatype);
					}

					if (DateType.equals("Float")) {
						String minResponseValue_sq_float = request.getParameterValues("minResponseValue_sq_float")[0];
						String maxResponseValue_sq_float = request.getParameterValues("maxResponseValue_sq_float")[0];
						String maxResponses_sq_float = request.getParameterValues("maxResponses_sq_float")[0];
						if (!maxResponses_sq_float.equals("")) {
							question.setMaxResponses(Long.valueOf(maxResponses_sq_float));
						}
						question.setMinResponseValue(minResponseValue_sq_float);
						question.setMaxResponseValue(maxResponseValue_sq_float);
						if (request.getParameterValues("Units_float") != null) {
							String u1 = request.getParameterValues("Units_float")[0];
							// if (!u1.equals("") || !u1.equals("0")) {
							// Units units = unitsDAO.findById(u1);
							// type.setUnits(units);
							// }
							u1 = HtmlUtils.htmlEscape(u1);
							if (!u1.equals("")) {
								Units units = unitsDAO.findById(u1);
								if (units == null) {
									units = new Units();
									units.setCode(u1);
									units.setName(u1);
									units.setDescription(u1);
									unitsDAO.save(units);
								}
								type.setUnits(units);
							}

						}
						DataType datatype = dataTypeDAO.findById("Float");
						type.setDataType(datatype);
					}
					type.setModifiedOn(new Date());
					type.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
					type.setDynamic(false);
					responseTypeDAO.save(type);
					question.setResponseType(type);
				}
			}
		}
		if (TypeName.equals("Dynamic")) {
			if (request.getParameterValues("Dynamic_DataType") != null) {
				DateType = request.getParameterValues("Dynamic_DataType")[0];
			}
			if (!ResponseTypeId.equals("")) {
				ResponseType type = responseTypeDAO.findById(Long.valueOf(ResponseTypeId));
				question.setResponseType(type);
				if (!DateType.equals("0")) {
					type.setDataType(dataTypeDAO.findById(DateType));
				}
			}

			// only checkbox
			String maxResponses_sq_checkbox = request.getParameterValues("maxResponses_sq_checkbox")[0];
			if (!maxResponses_sq_checkbox.equals("")) {
				question.setMaxResponses(Long.valueOf(maxResponses_sq_checkbox));
			}

		}
		String displayWidth = request.getParameterValues("display_width")[0];
		if (displayWidth != null && !displayWidth.equals("")) {
			if (question.getWidth().equals("")) {
				question.setWidth(displayWidth);
			}
		}
		QuestionAvailabilityType avaiability = new QuestionAvailabilityType();
		QuestionStatusType status = new QuestionStatusType();
		// When row is first created, the status is set to "Active"
		// When row is first created, the availability is set to "Open"
		avaiability.setCode("open");
		status.setCode("active");
		question.setQuestionStatusType(status);
		question.setQuestionAvailabilityType(avaiability);
		if (question.getResponseType() == null) {
			// no select any responsetype ??
			if (!TypeName.equals("")) {
				try {
					ResponseType type = responseTypeDAO.findById(Long.valueOf(TypeName));
					question.setResponseType(type);
				} catch (Exception e) {
					request.getSession().removeAttribute("ResponseTypeId");
					return getViewNameByRequestURI(request);
				}

			}

		}
		if (!TypeName.equals("")) {
			try {
				ResponseType type = responseTypeDAO.findById(Long.valueOf(TypeName));
				if (type != null) {
					question.setResponseType(type);
				}
			} catch (Exception e) {
			}
		}
		// branch end
		String questionId = "";
		if (request.getParameterValues("questionId") != null) {
			questionId = request.getParameterValues("questionId")[0];
			question.setQuestionId(Long.valueOf(questionId));
		}
		String epaDataType = question.getResponseType().getDataType() == null ? null : question.getResponseType().getDataType().getCode();
		question.setEpaResponseDataType(epaDataType);
		question = escapeQuestion(question);
		//last update question 2009.7.1
		if (question.getQuestionId()== null && question.getVersion()==1L){
			GenericFunction fun = new GenericFunction();
			question.setRefId(fun.NextQuestionNumber(questionDAO.GetMaxNumber()));
		}
		
        question.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
		questionDAO.saveOrUpdate(question);
		request.getSession().removeAttribute("ResponseTypeId");
		sessionStatus.setComplete();
		// jump link
		// modify by messageMap
		if (request.getRequestURI().indexOf(CREATE_REQUEST) > -1) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + createQuestionSuccessMessage, request, messageSource, null);

		}
		if (request.getRequestURI().indexOf(NEW_VERSION_REQUEST) > -1) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + createNewVersionQuestionMessage, request, messageSource, null);

		}
		if (request.getRequestURI().indexOf(EDIT_REQUEST) > -1) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + editQuestionSuccessMessage, request, messageSource, null);

		}
		if (request.getRequestURI().indexOf(COPY_REQUEST) > -1) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + copyQuestionSuccessMessage, request, messageSource, null);

		}
		if (StringUtils.equalsIgnoreCase(submitAction, SUBMIT)) {
			return redirectPrefix + VIEW_REQUEST + requestSuffix + "?id=" + String.valueOf(question.getQuestionId().intValue());
		}

		if (StringUtils.equalsIgnoreCase(submitAction, SUBMIT_AND_NEW)) {
			return redirectPrefix + CREATE_REQUEST + requestSuffix;
		}

		if (StringUtils.equalsIgnoreCase(submitAction, SUBMIT_AND_EXIT)) {
			return redirectPrefix + LIST_REQUEST + requestSuffix + "?checkSearch=list";
		}
		return redirectPrefix + CREATE_REQUEST + requestSuffix;
	}

	@Transactional(readOnly = true)
	@RequestMapping(value = { VIEW_REQUEST, RETIRE_REQUEST }, method = RequestMethod.GET)
	public String viewQuestion(@RequestParam
	String id, ModelMap model, HttpServletRequest request) {
		// message ??
		readMessages(defaultQuestionMessageKeys, request);
		readMessages(MessageKeys, request);

		Question question = questionManager.getQuestionById(id);
		if (question == null) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + emptyQuestionMessage, request, messageSource, null);
			readMessages(defaultQuestionMessageKeys, request);
			return errorsViewName;
		}
		if (request.getRequestURI().indexOf(RETIRE_REQUEST) > -1) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + questionRetireConfirmMessage, request, messageSource, null);
			readMessages(defaultQuestionMessageKeys, request);
		}
		String responseName = "";
		String uiControlName = "";
		String dateTypeName = "";
		ResponseType type = question.getResponseType();
		if (question.getResponseType().getName() == null || question.getResponseType().getName().equals("")) {
			Boolean dynamic = question.getResponseType().getDynamic();
			dynamic = dynamic == null ? false : dynamic;
			if (dynamic == true) {
				responseName = "Dynamic";

			}
			if (dynamic == false) {
				responseName = "Custom";
			}

			uiControlName = type.getUicontrol() == null ? "" : type.getUicontrol().getName();
			dateTypeName = type.getDataType() == null ? "" : type.getDataType().getName();
			List lresponseEntity = questionManager.getEntity(type.getResponseTypeId().toString());
			model.addAttribute("lresponseEntity", comparator(lresponseEntity));
			model.addAttribute("entitys", lresponseEntity.size());
		} else {
			responseName = question.getResponseType().getName();
		}
		model.addAttribute("uiControlName", uiControlName);
		model.addAttribute("dateTypeName", dateTypeName);
		model.addAttribute("responseName", responseName);
		model.addAttribute("responseId", question.getResponseType().getResponseTypeId().toString());

		if (type.getUnits() != null) {
			model.addAttribute("units", type.getUnits().getName());
		} else {
			model.addAttribute("units", "");
		}
		if (type.getDataValidation() != null) {
			model.addAttribute("mask", type.getDataValidation().getDescription());
		} else {
			model.addAttribute("mask", "");
		}
		model.addAttribute("currentAdmin", question.getModifiedBy().getUsername());
		model.addAttribute("question", question);
		model.addAttribute("retireon", (new Date()));
		String status = "";
		if (question.getQuestionStatusType() != null) {
			status = question.getQuestionStatusType().getCode();
		}
		String from = "";
		if (request.getParameterValues("from") != null) {
			from = request.getParameterValues("from")[0];
		}
		request.setAttribute("Msg_retire", getMessage("", retiredMessage));
		request.setAttribute("Msg_lock", getMessage("", lockedMessage));
		model.addAttribute("status", status);
		model.addAttribute("from", from);
		return getViewNameByRequestURI(request);
	}

	@Transactional()
	@RequestMapping(value = RETIRE_REQUEST, method = RequestMethod.POST)
	public String retireQuestion(@RequestParam
	String submitAction, @ModelAttribute("question")
	Question question, Errors errors, ModelMap model, HttpServletRequest request) {
		CustomUserDetails currentAdmin = SecurityUtils.getCurrentUser();
		// If the retired note is empty, return to the form, and display a
		// message.
		readMessages(defaultQuestionMessageKeys, request);
		readMessages(MessageKeys, request);
		if (StringUtils.isEmpty(question.getRetiredNote())) {
			addMessages(MESSAGE_KEY + "=" + questionRetireNoteMessage, request, messageSource, null);
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + questionRetireConfirmMessage, request, messageSource, null);
			return redirectPrefix + RETIRE_REQUEST + requestSuffix + "?id=" + String.valueOf(question.getQuestionId().intValue());
		}
		if (question.getRetiredNote().length() >= 255) {
			addMessages(MESSAGE_KEY + "=" + questionRetireNoteLenMessage, request, messageSource, null);
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + questionRetireConfirmMessage, request, messageSource, null);
			return redirectPrefix + RETIRE_REQUEST + requestSuffix + "?id=" + String.valueOf(question.getQuestionId().intValue());

		}
		question.setRetiredBy(userDAO.findById(currentAdmin.getUsername()));
		question.setRetiredOn(new Date());
		// question.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
		// question.setModifiedOn(new Date());
		question.setQuestionStatusType(questionStatusTypeDAO.findById("retired"));
		String epaDataType = question.getResponseType().getDataType() == null ? null : question.getResponseType().getDataType().getCode();
		question.setEpaResponseDataType(epaDataType);
		questionDAO.update(question);
		addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + questionRetireSuccessMessage, request, messageSource, null);
		if (StringUtils.equalsIgnoreCase(submitAction, SUBMIT)) {
			return redirectPrefix + VIEW_REQUEST + requestSuffix + "?id=" + String.valueOf(question.getQuestionId().intValue());
		}

		if (StringUtils.equalsIgnoreCase(submitAction, SUBMIT_AND_EXIT)) {
			return redirectPrefix + LIST_REQUEST + requestSuffix + "?checkSearch=list";
		}
		return redirectPrefix + VIEW_REQUEST + requestSuffix;
	}

	@Transactional(readOnly = true)
	@RequestMapping(value = EDIT_REQUEST, method = RequestMethod.GET)
	public String editQuestion(@RequestParam
	String id, ModelMap model, HttpServletRequest request) {
		CustomUserDetails currentAdmin = SecurityUtils.getCurrentUser();
		Question question = questionManager.getQuestionById(id);
		readMessages(defaultQuestionMessageKeys, request);
		// If the question is not existed, display the message.
		if (question == null) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + emptyQuestionMessage, request, messageSource, null);
			readMessages(defaultQuestionMessageKeys, request);
			return errorsViewName;
		}
		if (question.getQuestionAvailabilityType().getCode().equals("locked") || question.getQuestionStatusType().getCode().equals("retired")) {

			return redirectTo403();

		}
		if (!question.getModifiedBy().getUserGroup().getName().equals(currentAdmin.getGroupName())) {
			return redirectTo403();
		}
		// QResponsetype
		request.getSession().setAttribute("ResponseTypeId", question.getResponseType().getResponseTypeId().toString());
		createFirst(model);
		String responseName = "";
		String uiControlName = "";
		String dateTypeName = "";
		// TO-DO modify by new reponse type
		String ResponseTypeId = "";
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
		}
		ResponseType type = question.getResponseType();

		if (type.getName() == null || type.getName().equals("")) {
			Boolean dynamic = type.getDynamic()==null?false:type.getDynamic();
			if (dynamic == true) {
				responseName = "Dynamic";

			}
			if (dynamic == false) {
				responseName = "Custom";
			}
			uiControlName = type.getUicontrol() == null ? "" : type.getUicontrol().getName();
			dateTypeName = type.getDataType() == null ? "" : type.getDataType().getName();
			List lresponseEntity = questionManager.getEntity(type.getResponseTypeId().toString());
			model.addAttribute("lresponseEntity", comparator(lresponseEntity));
			model.addAttribute("entitys", lresponseEntity.size());
		} else {
			responseName = question.getResponseType().getName();
		}
		String from = "";
		if (request.getParameterValues("from") != null) {
			from = request.getParameterValues("from")[0];
		}
		List<QuestionSet> questionSets = questionManager.getByQuestion(id);

		model.addAttribute("questionSets", questionSets);
		request.setAttribute(MESSAGE_WHEREUSERD_KEY, this.getMessage(String.valueOf(questionSets.size()), publicFoundMessage));
		request.setAttribute("Msg_retire", getMessage("", pageRetiredMessage));
		request.setAttribute("Msg_lock", getMessage("", pageLockedMessage));

		model.addAttribute("from", from);
		model.addAttribute("uiControlName", uiControlName);
		model.addAttribute("dateTypeName", dateTypeName);
		model.addAttribute("responseName", responseName);
		model.addAttribute("responseId", question.getResponseType().getResponseTypeId().toString());
		model.addAttribute(dateTypeName, dateTypeName);
		model.addAttribute("isEdit", EDIT_FLAG);
		request.setAttribute(DEFAULT_QUESTION_MESSAGE_KEY, getMessage("", copyMessage));
		errorMessage(model);
		// addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + copyMessage,
		// request, messageSource, null);
		model.addAttribute("question", question);
		return getViewNameByRequestURI(request);
	}

	/**
	 * List QuestionSets refered by this question
	 * 
	 * @param QId
	 *            question id
	 * @param model
	 * @return
	 */
	@RequestMapping(value = WHERE_USED_REQUEST, method = RequestMethod.GET)
	public String whereUsed(@RequestParam(required = false)
	Integer page, @RequestParam
	String id, HttpServletRequest request, ModelMap model) {

		// If the page number is null, then set as 1.
		page = page == null ? 1 : page;
		Pager pager = new Pager();
		// Set the current page number.
		pager.setPage(page);
		pager.setRootUrl(request.getRequestURI());

		// List<QuestionSet> questionSets =
		// questionSetDAO.findByQuestion(id,pager);
		List<QuestionSet> questionSets = questionManager.getByQuestion(id);
		model.addAttribute("question", questionDAO.findById(new Long(id)));
		model.addAttribute("questionSets", questionSets);
		request.setAttribute(MESSAGE_KEY, this.getMessage(String.valueOf(questionSets.size()), publicFoundMessage));
		request.setAttribute("Msg_retire", getMessage("", pageRetiredMessage));
		request.setAttribute("Msg_lock", getMessage("", pageLockedMessage));
		return "designer.question.whereused";
	}

	/**
	 * The method is used to render the page before display the create new
	 * Version question page. If you want to put a model into requestScope, use
	 * method addAttribute in {@link ModelMap}.
	 * 
	 * @param model
	 * @return
	 */
	@Transactional()
	@RequestMapping(value = NEW_VERSION_REQUEST, method = RequestMethod.GET)
	public String entryNewVersionQuestion(@RequestParam
	String id, ModelMap model, HttpServletRequest request) {
		CustomUserDetails currentAdmin = SecurityUtils.getCurrentUser();
		/**
		 * If the Question is in Retired status, it cannot be versioned. The web
		 * site will prompt the Author with the message 鈥淭his action not
		 * available; Question is in Retired Status鈥�
		 */
		Question old_question = questionManager.getQuestionById(id);
		if (!old_question.getModifiedBy().getUserGroup().getName().equals(currentAdmin.getGroupName())) {

			return redirectTo403();
		}
		if (old_question.getQuestionStatusType().getCode().equals("retired")) {
			addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + retiredMessage, request, messageSource, null);
			readMessages(defaultQuestionMessageKeys, request);
			return redirectPrefix + VIEW_REQUEST + requestSuffix + "?id=" + id;
		}
		Question question = new Question();
		question.setRefId(old_question.getRefId());
		/**
		 * find max version of this question
		 */
		question.setVersion(Long.valueOf(questionManager.getNextVersionQuetion(id)));
		question.setModifiedOn(new Date());
		question.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
		question.setDescription(old_question.getDescription());
		question.setHelpText(old_question.getHelpText());
		question.setMaxResponses(old_question.getMaxResponses());
		question.setMaxResponseValue(old_question.getMaxResponseValue());
		question.setMinResponseValue(old_question.getMinResponseValue());
		question.setName(old_question.getName());
		question.setVocabularyname(old_question.getVocabularyname());
		question.setRows(old_question.getRows());
		question.setText(old_question.getText());
		question.setWidth(old_question.getWidth());
		// ResponseTypeId
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			request.getSession().removeAttribute("ResponseTypeId");
		}
		// Copy new ResponseType object
		ResponseType oldType = responseTypeDAO.findById(old_question.getResponseType().getResponseTypeId());
		ResponseType newType = new ResponseType();
		// if typename is custom/dynamic
		if (oldType.getName() == null || oldType.getName().equals("")) {
			newType.setDataType(oldType.getDataType());
			newType.setDataValidation(oldType.getDataValidation());
			newType.setDynamic(oldType.getDynamic()==null?false:oldType.getDynamic());
			newType.setFrequency(oldType.getFrequency());
			newType.setId(oldType.getId());
			newType.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
			newType.setModifiedOn(new Date());
			newType.setUicontrol(oldType.getUicontrol());
			newType.setUnits(oldType.getUnits());
			responseTypeDAO.save(newType);
			// responseTypeDAO.saveResponseType(newType);
			// questionManager.saveEntity(newType);
			questionManager.copyEntity(old_question.getResponseType().getResponseTypeId().toString(), newType, userDAO.findById(currentAdmin.getUsername()));

			request.getSession().setAttribute("ResponseTypeId", newType.getResponseTypeId().toString());
		} else {
			request.getSession().setAttribute("ResponseTypeId", old_question.getResponseType().getResponseTypeId().toString());
		}

		QuestionAvailabilityType avaiability = new QuestionAvailabilityType();
		QuestionStatusType status = new QuestionStatusType();
		// When row is first created, the status is set to "Active"
		// When row is first created, the availability is set to "Open"
		avaiability.setCode("open");
		status.setCode("active");
		question.setQuestionStatusType(status);
		question.setQuestionAvailabilityType(avaiability);
		// find exist value
		List restype = questionManager.getResponseType();
		List datatype = dataTypeDAO.findAll();
		List datavilidate = dataValidationDAO.findAll();
		List units = unitsDAO.findAll();
		List uicontrols = uiControlDAO.findAll();
		List custom_uicontrol = new ArrayList();
		List dynamic_uicontrol = new ArrayList();
		/**
		 * If the Author chooses "Custom", the UI Control field will display the
		 * five HTML Forms controls: Radio Button, Check Box, Dropdown, Text Box
		 * and Text Area. If the Author chooses "Dynamic", the UI Control field
		 * will display only the following controls: Radio Button, Check Box and
		 * Dropdown.
		 */
		for (int i = 0; i < uicontrols.size(); i++) {
			UiControl ui = (UiControl) uicontrols.get(i);
			if (ui.getName().equals("Radio Button") || ui.getName().equals("Dropdown") || ui.getName().equals("Check Box")) {
				custom_uicontrol.add(ui);
				dynamic_uicontrol.add(ui);
			}
			if (ui.getName().equals("Text Box") || ui.getName().equals("Text Area")) {
				custom_uicontrol.add(ui);
			}

		}

		String responseName = "";
		String uiControlName = "";
		String dateTypeName = "";
		// TO-DO modify by new reponse type
		String ResponseTypeId = "";
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
		}
		ResponseType type;
		if (ResponseTypeId.equals("")) {
			type = question.getResponseType();
		} else {
			type = responseTypeDAO.findById(Long.valueOf(ResponseTypeId));
		}
		question.setResponseType(type);
		if (type.getName() == null || type.getName().equals("")) {
			Boolean dynamic = type.getDynamic()==null?false:type.getDynamic();
			if (dynamic == true) {
				responseName = "Dynamic";

			}
			if (dynamic == false) {
				responseName = "Custom";
			}
			uiControlName = type.getUicontrol() == null ? "" : type.getUicontrol().getName();
			dateTypeName = type.getDataType() == null ? "" : type.getDataType().getName();
			List lresponseEntity = questionManager.getEntity(type.getResponseTypeId().toString());
			model.addAttribute("lresponseEntity", comparator(lresponseEntity));
			model.addAttribute("entitys", lresponseEntity.size());
		} else {
			responseName = question.getResponseType().getName();
		}
		String from = "";
		if (request.getParameterValues("from") != null) {
			from = request.getParameterValues("from")[0];
		}
		model.addAttribute("from", from);
		model.addAttribute("uiControlName", uiControlName);
		model.addAttribute("dateTypeName", dateTypeName);
		model.addAttribute("responseName", responseName);
		model.addAttribute("responseId", old_question.getResponseType().getResponseTypeId().toString());
		// readMessages(defaultQuestionMessageKeys, request);
		addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + createNewVersionQuestionFirstMessage, request, messageSource, null);
		model.addAttribute("question", question);
		model.addAttribute("restype", restype);
		model.addAttribute("datavilidate", datavilidate);
		model.addAttribute("currentAdmin", currentAdmin);
		model.addAttribute("units", units);

		model.addAttribute("datatype", datatype);
		model.addAttribute("custom_uicontrol", custom_uicontrol);
		model.addAttribute("dynamic_uicontrol", dynamic_uicontrol);
		errorMessage(model);
		readMessages(defaultQuestionMessageKeys, request);
		return getViewNameByRequestURI(request);
	}

	/**
	 * The method is used to render the page before display the create new
	 * Version question page. If you want to put a model into requestScope, use
	 * method addAttribute in {@link ModelMap}.
	 * 
	 * @param model
	 * @return
	 */
	@Transactional
	@RequestMapping(value = COPY_REQUEST, method = RequestMethod.GET)
	public String entryCopyQuestion(@RequestParam
	String id, ModelMap model, HttpServletRequest request) {
		CustomUserDetails currentAdmin = SecurityUtils.getCurrentUser();
		/**
		 * If the Question is in Retired status, it cannot be versioned. The web
		 * site will prompt the Author with the message 鈥淭his action not
		 * available; Question is in Retired Status鈥�
		 */
		Question old_question = questionManager.getQuestionById(id);
		Question question = new Question();

		question.setModifiedOn(new Date());
		question.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
		question.setDescription(old_question.getDescription());
		question.setHelpText(old_question.getHelpText());
		question.setMaxResponses(old_question.getMaxResponses());
		question.setMaxResponseValue(old_question.getMaxResponseValue());
		question.setMinResponseValue(old_question.getMinResponseValue());
		question.setName(old_question.getName());
		question.setVocabularyname(old_question.getVocabularyname());
		question.setRows(old_question.getRows());
		question.setText(old_question.getText());
		question.setWidth(old_question.getWidth());

		if (!old_question.getModifiedBy().getUserGroup().getName().equals(currentAdmin.getGroupName())) {
			return redirectTo403();
		}
		// ResponseTypeId
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			request.getSession().removeAttribute("ResponseTypeId");
		}
		// Copy new ResponseType object
		ResponseType oldType = responseTypeDAO.findById(old_question.getResponseType().getResponseTypeId());
		ResponseType newType = new ResponseType();
		// if typename is custom/dynamic
		if (oldType.getName() == null || oldType.getName().equals("")) {
			newType.setDataType(oldType.getDataType());
			newType.setDataValidation(oldType.getDataValidation());
			newType.setDynamic(oldType.getDynamic()==null?false:oldType.getDynamic());
			newType.setFrequency(oldType.getFrequency());
			newType.setId(oldType.getId());
			newType.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
			newType.setModifiedOn(new Date());
			newType.setUicontrol(oldType.getUicontrol());
			newType.setUnits(oldType.getUnits());
			responseTypeDAO.save(newType);
			// responseTypeDAO.saveResponseType(newType);
			// questionManager.saveEntity(newType);
			questionManager.copyEntity(old_question.getResponseType().getResponseTypeId().toString(), newType, userDAO.findById(currentAdmin.getUsername()));
			// copy response entity
			request.getSession().setAttribute("ResponseTypeId", newType.getResponseTypeId().toString());
		} else {
			request.getSession().setAttribute("ResponseTypeId", old_question.getResponseType().getResponseTypeId().toString());
		}
		// update by last 2009.7.1
		//GenericFunction fun = new GenericFunction();
		//question.setRefId(fun.NextQuestionNumber(questionDAO.GetMaxNumber()));
		question.setVersion(Long.valueOf("1"));
		question.setModifiedOn(new Date());
		question.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
		QuestionAvailabilityType avaiability = new QuestionAvailabilityType();
		QuestionStatusType status = new QuestionStatusType();
		// When row is first created, the status is set to "Active"
		// When row is first created, the availability is set to "Open"
		avaiability.setCode("open");
		status.setCode("active");
		question.setQuestionStatusType(status);
		question.setQuestionAvailabilityType(avaiability);
		// find exist value
		List restype = questionManager.getResponseType();
		List datatype = dataTypeDAO.findAll();
		List datavilidate = dataValidationDAO.findAll();
		List units = unitsDAO.findAll();
		List uicontrols = uiControlDAO.findAll();
		List custom_uicontrol = new ArrayList();
		List dynamic_uicontrol = new ArrayList();
		/**
		 * If the Author chooses "Custom", the UI Control field will display the
		 * five HTML Forms controls: Radio Button, Check Box, Dropdown, Text Box
		 * and Text Area. If the Author chooses "Dynamic", the UI Control field
		 * will display only the following controls: Radio Button, Check Box and
		 * Dropdown.
		 */
		for (int i = 0; i < uicontrols.size(); i++) {
			UiControl ui = (UiControl) uicontrols.get(i);
			if (ui.getName().equals("Radio Button") || ui.getName().equals("Dropdown") || ui.getName().equals("Check Box")) {
				custom_uicontrol.add(ui);
				dynamic_uicontrol.add(ui);
			}
			if (ui.getName().equals("Text Box") || ui.getName().equals("Text Area")) {
				custom_uicontrol.add(ui);
			}

		}

		String responseName = "";
		String uiControlName = "";
		String dateTypeName = "";
		// TO-DO modify by new reponse type
		String ResponseTypeId = "";
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
		}
		ResponseType type;
		if (ResponseTypeId.equals("")) {
			type = question.getResponseType();
		} else {
			type = responseTypeDAO.findById(Long.valueOf(ResponseTypeId));
		}

		if (type.getName() == null || type.getName().equals("")) {
			Boolean dynamic = type.getDynamic()==null?false:type.getDynamic();
			if (dynamic == true) {
				responseName = "Dynamic";

			}
			if (dynamic == false) {
				responseName = "Custom";
			}
			uiControlName = type.getUicontrol() == null ? "" : type.getUicontrol().getName();
			dateTypeName = type.getDataType() == null ? "" : type.getDataType().getName();
			List lresponseEntity = questionManager.getEntity(type.getResponseTypeId().toString());
			model.addAttribute("lresponseEntity", comparator(lresponseEntity));
			model.addAttribute("entitys", lresponseEntity.size());
		} else {
			responseName = old_question.getResponseType().getName();
		}
		String from = "";
		if (request.getParameterValues("from") != null) {
			from = request.getParameterValues("from")[0];
		}
		model.addAttribute("from", from);
		model.addAttribute("uiControlName", uiControlName);
		model.addAttribute("dateTypeName", dateTypeName);
		model.addAttribute("responseName", responseName);
		model.addAttribute("responseId", old_question.getResponseType().getResponseTypeId().toString());
		addMessages(DEFAULT_QUESTION_MESSAGE_KEY + "=" + copyMessage, request, messageSource, null);
		model.addAttribute("question", question);
		model.addAttribute("restype", restype);
		model.addAttribute("datavilidate", datavilidate);
		model.addAttribute("currentAdmin", currentAdmin);
		model.addAttribute("units", units);
		model.addAttribute("datatype", datatype);
		model.addAttribute("custom_uicontrol", custom_uicontrol);
		model.addAttribute("dynamic_uicontrol", dynamic_uicontrol);
		model.addAttribute("newType", newType);
		errorMessage(model);
		readMessages(defaultQuestionMessageKeys, request);
		return getViewNameByRequestURI(request);
	}

	/**
	 * List this responseentity of responsetype
	 * 
	 * @param Rid
	 * @param model
	 * @param request
	 * @param sessionStatus
	 * @param response
	 * @return
	 */
	@Transactional
	@RequestMapping(value = LIST_RESPONSE_REQUEST, method = RequestMethod.POST)
	public String processListResponse(@RequestParam
	String Rid, ModelMap model, HttpServletRequest request, SessionStatus sessionStatus, HttpServletResponse response) {
		String Check = (request.getParameter("Check") == null ? "" : request.getParameter("Check"));
		if (!Rid.trim().equals("")) {
			String outentity = "";
			if (!Check.equals("")) {
				outentity = questionManager.getResponsetEntity(Rid, true);
			} else {
				outentity = questionManager.getResponsetEntity(Rid, false);
			}
			PrintWriter out = null;
			try {
				out = response.getWriter();
			} catch (IOException e) {
				return errorsViewName;
			}
			out.print(outentity);
		}
		return null;
	}

	@Transactional
	@RequestMapping(value = CHECK_REQUEST, method = RequestMethod.POST)
	public String checkResponse(ModelMap model, HttpServletRequest request, SessionStatus sessionStatus, HttpServletResponse response) {
		// check exist response
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			// delete from response entity
			String ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
			questionManager.delEntity(ResponseTypeId);
			// delete from response type
			ResponseType type = responseTypeDAO.findById(Long.valueOf(ResponseTypeId));
			responseTypeDAO.delete(type);
			// remove session(ResponseTypeId)
			request.getSession().removeAttribute("ResponseTypeId");
		}
		return null;
	}

	@Transactional
	@RequestMapping(value = CHECK_HAVE_REQUEST, method = RequestMethod.POST)
	public String checkhaveResponse(ModelMap model, HttpServletRequest request, SessionStatus sessionStatus, HttpServletResponse response) {
		// check exist response
		PrintWriter out = null;
		try {
			out = response.getWriter();
		} catch (IOException e) {
			return errorsViewName;
		}
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			// delete from response entity
			String ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
			// check exist items
			List Lentity = questionManager.getEntity(ResponseTypeId);
			if (Lentity.size() > 0 && Lentity.get(0) != null) {
				out.print("1");
			}
		}

		out.print("0");
		return null;
	}

	@Transactional
	@RequestMapping(value = ADD_RESPONSE_REQUEST, method = RequestMethod.POST)
	public String processCreateResponse(ModelMap model, HttpServletRequest request, SessionStatus sessionStatus, HttpServletResponse response) {
		CustomUserDetails currentAdmin = SecurityUtils.getCurrentUser();
		/**
		 * find exist responseType in session if cancel then delete from
		 * responseentity & responsetype if question save/edit complete then
		 * remove session(ResponseTypeId) if copy or edit question
		 * question.getresponsetype()
		 */
		String ResponseTypeId = "";
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
		}
		String respid = request.getParameterValues("resp_id")[0];
		String label = request.getParameterValues("resp_label")[0].trim();
		String labelvalue = request.getParameterValues("resp_value")[0].trim();
		String TypeName = request.getParameterValues("Responsetype")[0].trim();
		// replace special string
		label = HtmlUtils.htmlEscape(label);
		labelvalue = HtmlUtils.htmlEscape(labelvalue);
		// label = label.replaceAll(" ", "&nbsp;");
		// labelvalue = labelvalue.replaceAll(" ", "&nbsp;");

		/**
		 * Customtype: $("#Custom_UIControl").val(), Dynamictype:
		 * $("#Dynamic_UIControl").val()
		 */
		String CustomTypeName = request.getParameterValues("Customtype")[0];
		String DynamicTypeName = request.getParameterValues("Dynamictype")[0];
		String UiTypeName = "";
		if (TypeName.equals("Custom")) {
			UiTypeName = CustomTypeName;
		}
		if (TypeName.equals("Dynamic")) {
			UiTypeName = DynamicTypeName;
		}
		/**
		 * In order to enable the Author to create other types of Responses, the
		 * UI will render two additional values in the Response Type dropdown.
		 * They are "Custom" and "Dynamic" and should be at the top of the list.
		 * Choosing either one of these values will insert a row into the
		 * ResponseType table, with a blank value for Name. When the UI
		 * retrieves and builds the list for the Response Type dropdown, it will
		 * only select rows with non-blank values in Name and add the two values
		 * at the top of the list.
		 */
		UiControl ui = questionManager.getUIbyName(UiTypeName);
		// First time for responsetype
		if (ResponseTypeId.equals("")) {
			ResponseType type = new ResponseType();
			type.setModifiedOn(new Date());
			type.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
			type.setUicontrol(ui);
			if (TypeName.equals("Custom")) {
				type.setDynamic(false);
				responseTypeDAO.save(type);
			}
			if (TypeName.equals("Dynamic")) {
				type.setDynamic(true);
				responseTypeDAO.save(type);
			}
			request.getSession().setAttribute("ResponseTypeId", type.getResponseTypeId().toString());
			ResponseTypeId = type.getResponseTypeId().toString();
		}
		ResponseType ThisType = responseTypeDAO.findById(Long.valueOf(ResponseTypeId));
		// ------------------------------

		if (respid != null && !respid.equals("")) {
			// update
			ResponseEntry entity = responseEntryDAO.findById(Long.valueOf(respid));
			entity.setLabel(label);
			entity.setValue(labelvalue);
			entity.setModifiedOn(new Date());
			entity.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
			try {
				responseEntryDAO.update(entity);
			} catch (Exception e) {
				e.printStackTrace();
			}
		} else {
			// create
			ResponseEntry entity = new ResponseEntry();
			String sequence = "";
			if (ThisType != null) {
				sequence = questionManager.getMaxResponsetEntity(ThisType.getResponseTypeId().toString());
			} else {
				sequence = questionManager.getMaxResponsetEntity(ResponseTypeId);
			}

			entity.setSequence(Long.valueOf(Integer.valueOf(sequence) + 1));
			entity.setLabel(label);
			entity.setValue(labelvalue);
			entity.setModifiedOn(new Date());
			entity.setModifiedBy(userDAO.findById(currentAdmin.getUsername()));
			entity.setResponseType(ThisType);
			try {
				responseEntryDAO.save(entity);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		String outentity = "";
		if (ThisType != null) {
			outentity = questionManager.getResponsetEntity(ThisType.getResponseTypeId().toString(), false);
		} else {
			outentity = questionManager.getResponsetEntity(ResponseTypeId, false);
		}
		PrintWriter out = null;
		try {
			out = response.getWriter();
		} catch (IOException e) {
			return errorsViewName;
		}
		out.print(outentity);
		return null;
	}

	@Transactional
	@RequestMapping(value = DEL_RESPONSE_REQUEST, method = RequestMethod.POST)
	public String processDelResponse(ModelMap model, HttpServletRequest request, SessionStatus sessionStatus, HttpServletResponse response) {
		String Rid = request.getParameterValues("Rid")[0];
		if (!Rid.trim().equals("")) {
			questionManager.delResponsetEntity(Rid);
			String ResponseTypeId = "";
			if (request.getSession().getAttribute("ResponseTypeId") != null) {
				ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
			}
			String outentity = questionManager.getResponsetEntity(ResponseTypeId, false);
			PrintWriter out = null;
			try {
				out = response.getWriter();
			} catch (IOException e) {
				return errorsViewName;
			}
			out.print(outentity);
		}
		return null;
	}

	@Transactional
	@RequestMapping(value = MOVE_UP_REQUEST, method = RequestMethod.POST)
	public String processMoveupResponse(ModelMap model, HttpServletRequest request, SessionStatus sessionStatus, HttpServletResponse response) {
		String Rid = request.getParameterValues("Rid")[0];
		// String TypeName = request.getParameterValues("Responsetype")[0];
		String ResponseTypeId = "";
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
		}
		if (!Rid.trim().equals("")) {
			questionManager.moveUpEntity(ResponseTypeId, Rid);
			String outentity = questionManager.getResponsetEntity(ResponseTypeId, false);
			PrintWriter out = null;
			try {
				out = response.getWriter();
			} catch (IOException e) {
				return errorsViewName;
			}
			out.print(outentity);
		}
		return null;
	}

	@Transactional
	@RequestMapping(value = MOVE_DOWN_REQUEST, method = RequestMethod.POST)
	public String processMovedownResponse(ModelMap model, HttpServletRequest request, SessionStatus sessionStatus, HttpServletResponse response) {
		String Rid = request.getParameterValues("Rid")[0];
		// String TypeName = request.getParameterValues("Responsetype")[0];
		String ResponseTypeId = "";
		if (request.getSession().getAttribute("ResponseTypeId") != null) {
			ResponseTypeId = (String) request.getSession().getAttribute("ResponseTypeId");
		}
		if (!Rid.trim().equals("")) {
			questionManager.moveDownEntity(ResponseTypeId, Rid);
			String outentity = questionManager.getResponsetEntity(ResponseTypeId, false);
			PrintWriter out = null;
			try {
				out = response.getWriter();
			} catch (IOException e) {
				return errorsViewName;
			}
			out.print(outentity);
		}
		return null;
	}

	@Transactional()
	@RequestMapping(value = { CHECK_QUESTION_STATUE, DEL_REQUEST }, method = RequestMethod.POST)
	public String checkQuestion(@RequestParam
	String id, ModelMap model, HttpServletRequest request, HttpServletResponse response) {
		Question question = questionManager.getQuestionById(id);
		String message = "";
		/**
		 * If the Question availability is locked it cannot be updated directly.
		 * The web site will prompt the Author with the message this action not
		 * available; Question is in Locked Availability
		 */
		if (question.getQuestionAvailabilityType() != null && question.getQuestionAvailabilityType().getCode().equals("locked")) {
			message = this.getMessage("", lockedMessage);
		}
		/**
		 * If the Question is in Retired status, it cannot be updated directly.
		 * The web site will prompt the Author with the message 鈥淭his action
		 * not available; Question is in Retired Status鈥�
		 */
		if (question.getQuestionStatusType() != null && question.getQuestionStatusType().getCode().equals("retired")) {
			message = this.getMessage("", retiredMessage);
		}

		if (request.getRequestURI().indexOf(DEL_REQUEST) > -1) {
			if (!question.getQuestionInSets().isEmpty()) {
				message = this.getMessage("", includeMessage);
			}
		}

		PrintWriter out = null;
		try {
			out = response.getWriter();
		} catch (IOException e) {
			return errorsViewName;
		}
		if (!message.equals("")) {
			out.print("<font color='red'>" + message + "</font>");
		} else {
			if (request.getRequestURI().indexOf(DEL_REQUEST) > -1) {
				questionDAO.delete(question);
				out.print(this.getMessage(question.getRefId(), deletedMessage) + ":true");// Question
																							// has
																							// been
																							// deleted
			} else {
				out.print(message);
			}
		}
		return null;
	}

	@Transactional()
	@RequestMapping(value = CHECK_CREATE_REQUEST, method = RequestMethod.POST)
	public String processCheckQuestion(@ModelAttribute("question")
	Question question, Errors errors, HttpServletRequest request, HttpServletResponse response, ModelMap model, SessionStatus sessionStatus) {
		// Question question = new Question();

		if (request.getParameterValues("name") != null) {
			question.setName(request.getParameterValues("name")[0]);
		}
		if (request.getParameterValues("vacabularyname") != null) {
			question.setVocabularyname(request.getParameterValues("vacabularyname")[0]);
		}
		if (request.getParameterValues("text") != null) {
			question.setText(request.getParameterValues("text")[0]);
		}
		if (request.getParameterValues("helpText") != null) {
			question.setHelpText(request.getParameterValues("helpText")[0]);
		}
		if (request.getParameterValues("description") != null) {
			question.setDescription(request.getParameterValues("description")[0]);
		}
		PrintWriter out = null;
		try {
			out = response.getWriter();
		} catch (IOException e) {
			return errorsViewName;
		}
		Map<String, List<String>> errorsMessages = questionValidator.invokeValidate(question, errors, request.getLocale());
		if (errors.hasErrors()) {
			String outHtml = "";
			List allErrors = errors.getAllErrors();
			for (int i = 0; i < allErrors.size(); i++) {
				FieldError err = (FieldError) allErrors.get(i);
				outHtml += err.getField() + ":" + getMessage(err.getField(), err.getCode()) + ";";
			}
			out.print(outHtml);
		}
		out.print("");
		return null;
	}

	private void loadUsersAndGroupsInfoByPermission(CustomUserDetails currentUser, HttpServletRequest request) {
		List<String> permissions = currentUser.getPermissions();
		List<UserGroup> groups = new ArrayList();
		List<User> users = new ArrayList();
		if (permissions.contains(PermissionType.SYS_ADMIN.value())) {
			users = userDAO.findAll();
			request.setAttribute("users", users);
			groups = userGroupDAO.findAll();
			request.setAttribute("groups", groups);
		} else {
			groups.add(userGroupDAO.findById(currentUser.getGroupName()));
			if (permissions.contains(PermissionType.PORTAL_USER.value())) {
				users.add(userDAO.findById(currentUser.getUsername()));
			} else {
				users = questionManager.getUserByGroupId(currentUser.getGroupName());
			}
			request.setAttribute("users", users);
			request.setAttribute("groups", groups);
		}
		List<QuestionAvailabilityType> availabilities = questionAvailabiliTytypeDAO.findAll();
		List<QuestionStatusType> qsQuestionstatustypes = questionStatusTypeDAO.findAll();
		// output

		request.setAttribute("availabilities", availabilities);
		request.setAttribute("status", qsQuestionstatustypes);
	}

	public void createFirst(ModelMap model) {
		List restype = questionManager.getResponseType();
		List datatype = dataTypeDAO.findAll();
		List datavilidate = dataValidationDAO.findAll();
		List units = unitsDAO.findAll();
		List uicontrols = uiControlDAO.findAll();
		List custom_uicontrol = new ArrayList();
		List dynamic_uicontrol = new ArrayList();
		/**
		 * If the Author chooses "Custom", the UI Control field will display the
		 * five HTML Forms controls: Radio Button, Check Box, Dropdown, Text Box
		 * and Text Area. If the Author chooses "Dynamic", the UI Control field
		 * will display only the following controls: Radio Button, Check Box and
		 * Dropdown.
		 */
		for (int i = 0; i < uicontrols.size(); i++) {
			UiControl ui = (UiControl) uicontrols.get(i);
			if (ui.getName().equals("Radio Button") || ui.getName().equals("Dropdown") || ui.getName().equals("Check Box")) {
				custom_uicontrol.add(ui);
				dynamic_uicontrol.add(ui);
			}

			if (ui.getName().equals("Text Box") || ui.getName().equals("Text Area")) {
				custom_uicontrol.add(ui);
			}

		}
		// output
		model.addAttribute("restype", restype);
		model.addAttribute("datavilidate", datavilidate);
		model.addAttribute("units", units);
		model.addAttribute("datatype", datatype);
		model.addAttribute("custom_uicontrol", custom_uicontrol);
		model.addAttribute("dynamic_uicontrol", dynamic_uicontrol);
	}

	public void errorMessage(ModelMap model) {
		model.addAttribute("Msg_Responsetype", getMessage("", responseTypeMessage));
		model.addAttribute("Msg_UIControl", getMessage("", uiControlMessage));
		model.addAttribute("Msg_DataType", getMessage("", dataTypeMessage));
		model.addAttribute("Msg_Custom", getMessage("", customMessage));
		model.addAttribute("Msg_Invalid", getMessage("", invalidMessage));
		model.addAttribute("Msg_Width",getMessage("",this.emptyTextAreaWidthMessage));
		model.addAttribute("Msg_Rows",getMessage("",this.emptyTextAreaRowsMessage));
		model.addAttribute("Msg_SelectResponse", getMessage("", selectResponseMessage));
		model.addAttribute("Msg_ResponseLable", getMessage("", responseLableMessage));
		model.addAttribute("Msg_ResponseValue", getMessage("", responseValueMessage));
		model.addAttribute("Msg_Digital", getMessage("", digitalMessage));
		model.addAttribute("Msg_Integer", getMessage("", integerMessage));
		model.addAttribute("Msg_Date", getMessage("", dateMessage));
		model.addAttribute("Msg_MaxSelect", getMessage("", maxSelectMessage));
		model.addAttribute("Msg_MaxResponseInput", getMessage("", maxResponseInputMessage));
		model.addAttribute("Msg_MaxResponse", getMessage("", maxResponseMessage));
	}

	public Question initQuestion(String userName) {
		Question question = new Question();
		//GenericFunction fun = new GenericFunction();
		//update by last 2009.7.1
		//question.setRefId(fun.NextQuestionNumber(questionDAO.GetMaxNumber()));
		question.setVersion(Long.valueOf("1"));
		question.setModifiedOn(new Date());
		question.setModifiedBy(userDAO.findById(userName));
		QuestionAvailabilityType avaiability = new QuestionAvailabilityType();
		QuestionStatusType status = new QuestionStatusType();
		// When row is first created, the status is set to "Active"
		// When row is first created, the availability is set to "Open"
		avaiability.setCode("open");
		status.setCode("active");
		question.setQuestionStatusType(status);
		question.setQuestionAvailabilityType(avaiability);
		return question;
	}

	private Question escapeQuestion(Question question) {
		question.setName(HtmlUtils.htmlEscape(question.getName()));
		question.setText(question.getText());
		question.setVocabularyname(HtmlUtils.htmlEscape(question.getVocabularyname()));
		question.setDescription(HtmlUtils.htmlEscape(question.getDescription()));
		question.setHelpText(HtmlUtils.htmlEscape(question.getHelpText()));
		question.setRetiredNote(HtmlUtils.htmlEscape(question.getRetiredNote()));
		return question;
	}
	private List<ResponseEntry> comparator(List responseEntity){
		Object[] allData = responseEntity.toArray();
		Arrays.sort(allData, new MyComparator());
		List<ResponseEntry> NewResponses = new ArrayList();
		for (int i = 0; i < allData.length; i++) {
			NewResponses.add((ResponseEntry) allData[i]);
		}
		return NewResponses;
	}
}